package lowijs.XfDroid;

import static lowijs.XfDroid.FriendDBAdapter.KEY_CHANNEL_ID;
import static lowijs.XfDroid.XfDroidConstants.ARG_0;
import static lowijs.XfDroid.XfDroidConstants.SEPERATOR;
import static lowijs.XfDroid.XfDroidConstants.PREF_SOFT_NOTIFY;

import com.googlecode.xfdroid.R;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;

import lowijs.XfireClient.event.EventManager;
import lowijs.XfireClient.event.ToastEvent;
import lowijs.XfireClient.event.XfireEvent;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;

public class NotificationController {
	private static NotificationController INSTANCE;

	private int nextId;

	private NotificationManager manager;

	private NoteInfo compare;

	private List<NoteInfo> notes;

	private SharedPreferences prefs;

	private NotificationController(NotificationManager manager, SharedPreferences prefs) {
		this.manager = manager;
		this.prefs = prefs;

		compare = new NoteInfo();
		notes = new ArrayList<NoteInfo>();
		nextId = 3;
	}

	class NoteInfo implements Comparable<NoteInfo> {
		private int type;

		private long id;

		private int index;

		public NoteInfo() {
		}

		public int getType() {
			return type;
		}

		public void setType(int type) {
			this.type = type;
		}

		public long getId() {
			return id;
		}

		public void setId(long id) {
			this.id = id;
		}

		public int getIndex() {
			return index;
		}

		public void setIndex(int index) {
			this.index = index;
		}

		public int compareTo(NoteInfo another) {
			int compare = type - another.type;

			if (compare == 0) {
				if (id < another.id) {
					compare = -1;
				} else if (id > another.id) {
					compare = 1;
				}
			}

			return compare;
		}

		public NoteInfo copy() {
			NoteInfo ni = new NoteInfo();
			ni.id = id;
			ni.index = index;
			ni.type = type;
			return ni;
		}
	}

	public void notifyAppStatus(Context context, boolean online) {
		Notification application;

		String title = null;
		String text = null;

		if (online) {
			title = context.getString(R.string.xfdroid_connected);
			text = context.getString(R.string.xfdroid_connected_long);
			application = new Notification(R.drawable.xfire_online, title, System.currentTimeMillis());
		} else {
			title = context.getString(R.string.xfdroid_disconnected);
			text = context.getString(R.string.xfdroid_disconnected_long);
			application = new Notification(R.drawable.xfire_lost_notif, title, System.currentTimeMillis());
		}

		application.flags = online ? Notification.FLAG_ONGOING_EVENT : 0;
		application.defaults = 0;

		Intent fi = new Intent(context, Friendslist.class);
		fi.setFlags(Intent.FLAG_FROM_BACKGROUND | Intent.FLAG_ACTIVITY_SINGLE_TOP);
		PendingIntent pi = PendingIntent.getActivity(context, 0, fi, 0);
		application.setLatestEventInfo(context, title, text, pi);
		manager.cancel(1);
		manager.notify(1, application);
	}

	public void cancelUserNotifications(int useridAsInt) {
		int id = getUserNoteId(useridAsInt);
		manager.cancel(id);
	}

	public void notifyChannel(Context context, long channelid, String ticker, String who, String message) {
		int id = getChannelNoteId(channelid);
		Notification n = new Notification(R.drawable.xfire_notif, ticker, System.currentTimeMillis());
		n.flags |= Notification.FLAG_AUTO_CANCEL;
		n.defaults |= Notification.DEFAULT_ALL;
		Intent i = new Intent(context, ConvoWindow.class);
		Bundle extras = new Bundle();
		extras.putLong(KEY_CHANNEL_ID, channelid);
		i.putExtras(extras);
		i.setFlags(Intent.FLAG_FROM_BACKGROUND | Intent.FLAG_ACTIVITY_SINGLE_TOP);
		PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0);
		n.setLatestEventInfo(context, who, message, pi);
		manager.cancel(id);
		manager.notify(id, n);
	}

	private int getUserNoteId(long userid) {
		return getId(1, userid);
	}

	private int getChannelNoteId(long channelid) {
		return getId(2, channelid);
	}

	private synchronized int getId(int type, long id) {
		compare.type = type;
		compare.id = id;

		int index = Collections.binarySearch(notes, compare);

		if (index >= 0) {
			compare.index = notes.get(index).index;
		} else {
			compare.index = nextId++;
			index = (-index) - 1;
			notes.add(index, compare.copy());
		}

		return compare.index;
	}

	public void notifyAll(Context context, String[] results) {
		FriendDBAdapter db = FriendDBAdapter.getInstance(context);

		String splitOn = Pattern.quote(SEPERATOR);

		for (String str : results) {
			String[] parts = str.split(splitOn);
			long userid = Long.parseLong(parts[0]);
			int online = Integer.parseInt(parts[1]);
			String nickname = parts[2];
			Class<?> clazz = Friendslist.class;
			Bundle extras = new Bundle();

			if (nickname == null || nickname.equals("null") || nickname.trim().length() == 0) {
				continue;
			}

			String ticker = context.getString(online == FriendDBAdapter.OFFLINE_FLAG ? R.string.notif_user_offline : R.string.notif_user_online);
			ticker = ticker.replace(ARG_0, nickname);

			if (db.isPersistent(userid, online)) {
				if (online != FriendDBAdapter.OFFLINE_FLAG) {
					try {
						clazz = ConvoWindow.class;
						long channelid = db.openChannel(userid);
						extras.putLong(KEY_CHANNEL_ID, channelid);
					} catch (Exception e) {
					}
				}

				int id = getUserNoteId(userid);

				Notification n = new Notification(R.drawable.xfire_online, ticker, System.currentTimeMillis());
				n.flags |= Notification.FLAG_AUTO_CANCEL;

				Intent i = new Intent(context, clazz);
				i.putExtras(extras);
				i.setFlags(Intent.FLAG_FROM_BACKGROUND | Intent.FLAG_ACTIVITY_SINGLE_TOP);
				PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0);
				n.setLatestEventInfo(context, ticker, ticker, pi);

				manager.cancel(id);
				manager.notify(id, n);
			} else if (prefs.getBoolean(PREF_SOFT_NOTIFY, false)) {
				if (online == FriendDBAdapter.OFFLINE_FLAG) {
					// Cancel any active notifications of this user
					int uid = getUserNoteId(userid);
					manager.cancel(uid);
				}

				EventManager.fireEvent(new ToastEvent(XfireEvent.XF_TOAST, ticker));
			}
		}
	}

	public static NotificationController getInstance(Context context) {
		if (INSTANCE == null && context != null) {
			NotificationManager manager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
			INSTANCE = new NotificationController(manager, PreferenceManager.getDefaultSharedPreferences(context));
		}

		return INSTANCE;
	}

	public static void clearAll() {
		if (INSTANCE != null) {
			INSTANCE.manager.cancelAll();
		}
	}
}
